package cn.ztuo.bitrade.util;

import cn.ztuo.bitrade.constant.SysConstant;
import cn.ztuo.bitrade.entity.*;
import cn.ztuo.bitrade.service.ContractOrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class IndexPriceRunnable implements Runnable {

    private RedisUtil redisUtil;
    private KafkaTemplate<String, String> kafkaTemplate;
    private static Map<String, Long> robotMap = new HashMap<>();
    private static Map<String, String> tidMap = new HashMap<>();
    private RestTemplate restTemplate = new RestTemplate();
    private ContractOrderService orderService;
    private ContractCoin coin;
    private volatile static IndexPriceRunnable robotOrderRunnable;

    private IndexPriceRunnable() {

    }

    private IndexPriceRunnable(RedisUtil redisUtil, KafkaTemplate<String, String> kafkaTemplate, ContractOrderService orderService, ContractCoin coin) {
        this.redisUtil = redisUtil;
        this.kafkaTemplate = kafkaTemplate;
        this.orderService = orderService;
        this.restTemplate = new RestTemplate();
        this.coin = coin;
    }

    public static IndexPriceRunnable getInstance(RedisUtil redisUtil, KafkaTemplate<String, String> kafkaTemplate, ContractOrderService orderService, ContractCoin coin) {

        robotOrderRunnable = new IndexPriceRunnable(redisUtil, kafkaTemplate, orderService, coin);

        return robotOrderRunnable;
    }

    private void robotAddOrder() {
        try {
            synchronized (coin) {
                log.info("合约机器人--" + coin.getSymbol() + "--下单中.......");
                if(redisUtil.hasKey(SysConstant.CONTRACT_ROBOT_STATUS + coin.getSymbol())&&Integer.parseInt(redisUtil.get(SysConstant.CONTRACT_ROBOT_STATUS + coin.getSymbol()).toString())==0){
                    robotMap.remove(coin.getSymbol());
                    return;
                }
                ContractOrder order = new ContractOrder();
//                File file = new File("C:\\Users\\JH。\\Desktop\\source1\\" + coin.getSymbol());
//                if (!file.exists()) {
//                    // 文件不存在
//                    return;
//                }
//                String tradeInfo = DataUtil.readJsonFile("C:\\Users\\JH。\\Desktop\\source1\\" + coin.getSymbol());
                String tradeInfo =HttpsUtil.doGet("https://api.hbdm.com/swap-ex/market/trade?contract_code="+coin.getCoinSymbol()+"-USD");
                if (!tradeInfo.startsWith("{") || !tradeInfo.endsWith("}")) {
                    return;
                }
                JSONObject parse = JSON.parseObject(tradeInfo);
                if (parse.containsKey("status") && parse.getString("status").equals("ok")) {
                    JSONObject tick = parse.getJSONObject("tick");
                    if (!robotMap.containsKey(coin.getSymbol()) || (robotMap.containsKey(coin.getSymbol()) && robotMap.get(coin.getSymbol()).longValue() != tick.getLong("id").longValue())) {
                        robotMap.put(coin.getSymbol(), tick.getLong("id"));
                    } else {
                        return;
                    }

                    tick = tick.getJSONArray("data").getJSONObject(0);
                    order.setMemberId(1L);
                    order.setBaseSymbol(coin.getBaseSymbol());
                    order.setCoinSymbol(coin.getCoinSymbol());
                    order.setSymbol(coin.getSymbol());
                    if ("buy".equals(tick.getString("direction"))) {
                        order.setDirection(ContractOrderDirection.BUY);
                    }
                    if ("sell".equals(tick.getString("direction"))) {
                        order.setDirection(ContractOrderDirection.SELL);
                    }
                    order.setNowp(tick.getBigDecimal("amount"));
                    //赋值binance最新价格
                    String jsonObject = HttpsUtil.doGet("https://api.binance.com/api/v3/ticker/price");
                    List<JSONObject> priceList = JSON.parseArray(jsonObject,JSONObject.class);
                    if(priceList!=null&&priceList.size()>0){
                        ContractOrder finalOrder = order;
                        priceList.stream().filter(a->a.getString("symbol").equals(finalOrder.getSymbol().replaceAll("/",""))).forEach(a->{
                            finalOrder.setPrice(a.getBigDecimal("price"));
                        });
                        order =  finalOrder;
                    }else{
                        order.setPrice(tick.getBigDecimal("price"));
                    }
                    order.setType(ContractOrderType.LIMIT_PRICE);
                    order.setPositionFlag(ContractEnumType.ContractOrderPositionFlag.designate);
                    order = initRobotContractOrder(order);

                    if(order ==null ){
                        robotMap.remove(coin.getSymbol());
                        return;
                    }
                    log.info("开始添加挂单=====================================================");
                    MessageResult mr = orderService.addOrder(1L, order);
                    log.info("添加挂单成功=====================================================");
                    if (mr.getCode() != 0) {
                        log.info("提交订单失败:" + mr.getMessage());
                        return;
                    }
                    //计划单
                    //市价直接发送到 发送消息至Contract系统
                    kafkaTemplate.send("contract-order", order.getSymbol(), JSON.toJSONString(order));


                    Thread.sleep(2*1000);
                    order.setOrderId(null);
                    if ("buy".equals(tick.getString("direction"))) {
                        order.setDirection(ContractOrderDirection.SELL);
                    }
                    if ("sell".equals(tick.getString("direction"))) {
                        order.setDirection(ContractOrderDirection.BUY);
                    }

                    mr = orderService.addOrder(1L, order);
                    log.info("添加挂单成功=====================================================");
                    if (mr.getCode() != 0) {
                        log.info("提交订单失败:" + mr.getMessage());
                        return;
                    }
                    //计划单
                    //市价直接发送到 发送消息至Contract系统
                    kafkaTemplate.send("contract-order", order.getSymbol(), JSON.toJSONString(order));

                    Thread.sleep(2*1000);
                    log.info("结束le ================================");
                }else{
                    robotMap.remove(coin.getSymbol());
                }

                log.info("结束le ================================");
                if(redisUtil.hasKey(SysConstant.CONTRACT_ROBOT_STATUS + coin.getSymbol())&&Integer.parseInt(redisUtil.get(SysConstant.CONTRACT_ROBOT_STATUS + coin.getSymbol()).toString())==0){
                    robotMap.remove(coin.getSymbol());
                    return;
                }
                robotAddOrder();
            }
        } catch (Exception e) {
            log.info("撮合模块ERROR={}", e);
            robotAddOrder();
        }
    }

    private void addOrder(ContractOrder order) {
        log.info(coin.getSymbol() + "===开始匹配单=====================================================");
        if(order==null){
            return;
        }
        MessageResult mr = orderService.addOrder(1L, order);
        if (mr.getCode() != 0) {
            log.info("提交订单失败:" + mr.getMessage());
            return;
        }
        kafkaTemplate.send("contract-order", order.getSymbol(), JSON.toJSONString(order));
        log.info(Thread.currentThread().getName() + "匹配单线程阻塞========================");
    }
    @Override
    public void run() {
        robotAddOrder();
    }
    private ContractOrder initRobotContractOrder(ContractOrder order) {
        ContractCoin bySymbol = ContractUtils.getBaseSymbol(order.getSymbol());
        if (order.getDirection() == ContractOrderDirection.BUY) {
            if (order.getPositionFlag() == ContractEnumType.ContractOrderPositionFlag.designate) {
                order.setPositionType(ContractOrderPositionType.RISE);
            }
        }
        if (order.getDirection() == ContractOrderDirection.SELL) {
            if (order.getPositionFlag() == ContractEnumType.ContractOrderPositionFlag.designate) {
                order.setPositionType(ContractOrderPositionType.FALL);
            }
        }
        //委托数量和精度控制
        BigDecimal amount = BigDecimalUtils.mul(bySymbol.getMinVolume(), order.getNowp());
        order.setAmount(amount);
        //挂单操作成交量范围控制
        if (order.getPositionFlag() == ContractEnumType.ContractOrderPositionFlag.designate) {
            //只有普通挂单才冻结相应保证金;
            //起始保证金
            JSONObject map = ContractUtils.getStart(order.getAmount(), bySymbol, order.getNowp(), order.getMemberId(), null);
            if (map == null) {
                return null;
            }
            BigDecimal start = map.getBigDecimal("start");
            String startRate = map.getString("startRate");
            log.info("====================起始保证金:  " + start);

            //维持保证金
            JSONObject maintainMap = ContractUtils.getMaintain(order.getAmount(), bySymbol, order.getNowp(), order.getMemberId(), null);
            if (maintainMap == null) {
                return null;
            }
            BigDecimal maintain = maintainMap.getBigDecimal("maintain");
            String maintainRate = maintainMap.getString("maintainRate");
            log.info("====================维持保证金:  " + maintain);
            order.setStart(start);
            order.setStartRate(startRate);
            order.setMaintain(maintain);
            order.setMaintainRate(maintainRate);
        }
        order.setPositionValue(BigDecimalUtils.mul(order.getAmount(), order.getPrice()));
        order.setMemberId(1L);
        order.setTurnover(BigDecimal.ZERO);
        order.setSetTime(Calendar.getInstance().getTimeInMillis());
        return order;
    }

}